#ifndef __MY_SERVICE__
#define __MY_SERVICE__ 
#include "libary/httplib.h"
#include "Config.hpp"
#include "DataManage.hpp"
extern cloud::DataManager* data;
namespace cloud
{
    class Service
    {
    private:
        int _server_port;
        std::string _server_ip;
        std::string _download_prefix;
        httplib::Server _server;
    private:
        static void Upload(const httplib::Request& req, httplib::Response& rsp)
        {
            //查看客户端是否有上传文件
            auto ret = req.has_file("file");
            if(ret == false)
            {
                rsp.status = 404;
                return;
            }
            //将数据写到指定目录下
            const auto& file = req.get_file_value("file");
            std::string filename = FileUtil(file.filename).FileName();
            std::string realpath = Config::GetInstance()->GetBackDir() + filename;
            FileUtil fu(realpath);
            fu.SetContent(file.content);
            //更新备份信息
            BackupInfo info;
            info.NewBackupInfo(realpath, &info);
            data->Insert(info);
        }
        static std::string Totiemstr(time_t t)
        {
            std::string timestr = std::ctime(&t);
            return timestr;
        }
        static void ListShow(const httplib::Request& req, httplib::Response& rsp)
        {
            //1.获取所有备份文件的信息
            std::vector<BackupInfo> array;
            data->GetAll(&array);
            //2.根据文件信息返回html页面内容
            FileUtil fu("wwwroot/ListshowBeautify.html");
            std::string body;
            fu.GetContent(&body);
            std::stringstream ss;
            ss << body;
            ss << "</head><body><h1>Download</h1>";
            ss << "<table><tr><th>File Name</th>";
            ss << "<th class='right-align'>Date</th>";
            ss << "<th class='right-align'>Size</th>";
            ss << "</tr>";
            for(auto& a : array)
            {
                std::string filename = FileUtil(a.real_path).FileName();
                ss << "<tr>";
                ss << "<td><a href=" << a.url_path << ">" << filename << "</a></td>";
                ss << "<td class='right-align'>" << Totiemstr(a.atime) << "</td>";
                ss << "<td class='right-align'>" << a.fsize/1024 << "K" << "</td>";
                ss << "</tr>";
            }
            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
        }
        static std::string GetETag(const BackupInfo& info)
        {
            std::string etag = info.real_path;
            etag += "-";
            etag += std::to_string(info.fsize);
            etag += "-";
            etag += std::to_string(info.mtime);
            return etag;
        }
        static void Download(const httplib::Request& req, httplib::Response& rsp)
        {
            //1.根据请求资源路径获取文件备份信息
            BackupInfo info;
            data->GetOneByURL(req.path, &info);
            //2.根据文件备份信息判断是否已经压缩
            if(info.pack_flag == true)
            {
                //3.如果已经压缩，则进行解压缩,并且删除压缩文件
                FileUtil fu(info.pack_path);
                fu.UnCompress(info.real_path);
                fu.Remove();
                //4.修改备份文件信息
                info.pack_flag = false;
                data->Update(info);
            }
            bool retrans = false;
            std::string old_etag;
            if(req.has_header("If-Range"))
            {
                old_etag = req.get_header_value("If-Range");
                //有If-Range字段且，这个字段的值与请求文件的最新etag一致则符合断点续传
                if(old_etag == GetETag(info))
                {
                    retrans = true;
                }
            }
            //5.获取文件内容和修改头部字段
            FileUtil tmp(info.real_path);
            if(retrans == false)
            {
                tmp.GetContent(&rsp.body);
                //5.设置响应头部字段：ETag, Accept-Ranges:bytes
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("ETag", GetETag(info));
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 200;
            }
            else 
            {
                //httplib内部实现了对于区间请求也就是断点续传请求的处理
                //只需要我们用户将文件所有数据读取到rsp.body中，它内部会自动根据请求
                //区间，从body中取出指定区间数据进行响应
                //std::string range = req.get_header_val("Range"); bytes=start-end
                tmp.GetContent(&rsp.body);
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("ETag", GetETag(info));
                rsp.set_header("Content-Type", "application/octet-stream");
                //rsp.set_header("Content-Range", "bytes start-end/fsize");
                rsp.status = 206;//区间请求响应的是206
            }
           
        }
    public:
        Service()
        {
            Config* config = Config::GetInstance();
            _server_port = config->GetServerPort();
            _server_ip = config->GetServerIp();
            _download_prefix = config->GetDownloadPrefix();
        }
        void RunModule()
        {
            //1.注册方法表
            _server.Post("/upload", Upload);
            _server.Get("/listshow", ListShow);
            _server.Get("/", ListShow);
            _server.Get("/download/(.*)", Download);
            _server.listen(_server_ip, _server_port);
        }
    };
}
#endif